/*
 *  (C) Copyright 2008 Insula T.I. Ltda.
 * 
 *  This file is part of Vulcano.
 *
 *  Vulcano is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  Vulcano is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with Vulcano.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.openinsula.vulcano.orm.dao.hibernate;

import java.util.List;

import org.openinsula.vulcano.orm.dao.Dao;
import org.openinsula.vulcano.orm.dao.query.DaoQuery;
import org.openinsula.vulcano.orm.dao.query.DaoQueryVisitor;
import org.openinsula.vulcano.orm.dao.query.DistinctDaoQuery;
import org.openinsula.vulcano.orm.dao.query.ProjectionDaoQuery;
import org.openinsula.vulcano.orm.dao.query.PropertiesDaoQuery;
import org.openinsula.vulcano.orm.dao.query.SimpleDaoQuery;
import org.openinsula.vulcano.orm.dao.query.projection.Projection;
import org.openinsula.vulcano.orm.dao.query.projection.ProjectionVisitor;

/**
 * @author rebola
 * @author yanaga
 * @since 1.1
 * @see Dao
 * @see DaoQuery
 * @see HibernateDao
 */
public class FromHqlDaoQueryVisitor implements DaoQueryVisitor<String> {

	private final ProjectionVisitor<String> hqlVisitor = new HqlProjectionVisitor();

	public String visit(final DistinctDaoQuery<?> distinctDaoQuery) {
		String hql = String.format("select distinct %s from %s as %s%s", distinctDaoQuery.getQueryClass()
				.getCanonicalName(), distinctDaoQuery.getQueryClass().getCanonicalName(), HibernateDao.QUERY_ALIAS,
				whereClause(distinctDaoQuery));

		return hql;
	}

	public String visit(final ProjectionDaoQuery<?> projectionDaoQuery) {
		List<Projection> projections = projectionDaoQuery.getProjectionList();

		if (projections.size() == 0) {
			throw new IllegalArgumentException("At least one Projection must be specified.");
		}

		StringBuilder select = new StringBuilder();

		for (int i = 0; i < projections.size(); i++) {
			select.append(projections.get(i).accept(hqlVisitor));

			if (i < projections.size() - 1) {
				select.append(", ");
			}
		}

		String hql = String.format("select %s from %s as %s%s", select.toString(), projectionDaoQuery.getQueryClass()
				.getCanonicalName(), HibernateDao.QUERY_ALIAS, whereClause(projectionDaoQuery));

		return hql;
	}

	public String visit(final PropertiesDaoQuery<?> propertiesDaoQuery) {
		StringBuilder sb = new StringBuilder();
		List<String> propertyNames = propertiesDaoQuery.getPropertyNames();
		for (int i = 0; i < propertyNames.size(); i++) {
			sb.append(propertyNames.get(i));

			if (i < propertyNames.size() - 1) {
				sb.append(", ");
			}
		}

		String hql = String.format("select %s from %s as %s%s", sb.toString(), propertiesDaoQuery.getQueryClass()
				.getCanonicalName(), HibernateDao.QUERY_ALIAS, whereClause(propertiesDaoQuery));

		return hql;
	}

	public String visit(final SimpleDaoQuery<?> simpleDaoQuery) {
		String hql = String.format("from %s as %s%s", simpleDaoQuery.getQueryClass().getCanonicalName(),
				HibernateDao.QUERY_ALIAS, whereClause(simpleDaoQuery));

		return hql;
	}

	private String whereClause(final DaoQuery<?> daoQuery) {
		return daoQuery.getSpec() == null ? "" : " where ";
	}

}
